﻿using RestaurantClassLibrary;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace Restaurant.Controllers
{
    public class ReservationController : Controller
    {
        private RestaurantEntities db = new RestaurantEntities();

        //
        // GET: /Reservation/
        //returns the reservation tool menu page(make new reservation or make changes to existing)
        public ActionResult Index()
        {
            return View();
        }

        //
        //GET: /Reservation/Search
        //returns a view with form fields for searching existing reservations
        public ActionResult Search(DateTime? date = null, String name = "", String phoneNumber = "", bool fail = false)
        {
            //if action method was called following a failed search, display a message and pass back in the values of the failed search
            if (fail)
            {
                Reservation r = new Reservation { Date = (DateTime)date, Name = name, PhoneNumber = phoneNumber };
                ViewBag.Message = "We could not find a match for your search. Please try again:";
                return View(r);
            }
            else
            {
                ViewBag.Message = "";
                return View();
            }

        }

        //
        //POST: /Reservation/DoSearch
        //method to receive search data posted from the form in the search view
        [HttpPost]
        public ActionResult DoSearch(Reservation r)
        {
            //find the matching reservation if it exists in database
            Reservation result = db.Reservations.FirstOrDefault(res => res.Date == r.Date && res.Name.ToUpper() == r.Name.ToUpper() && res.PhoneNumber == r.PhoneNumber);
            //if no match found, redirect back to search page
            if (result == null)
            {
                return RedirectToAction("Search", new { date = r.Date, name = r.Name, phoneNumber = r.PhoneNumber, fail = true });
            }
            //match found, redirect to the details view for the reservation
            else
            {
                return RedirectToAction("Details", new { id = result.ID, isConfirmation = false });
            }
        }

        //
        // GET: /Reservation/Details/5
        //returns details view for specified reservtion id
        public ActionResult Details(int id = 0, bool isConfirmation = true)
        {
            //if this is confirmation of a new booking or change to a booking....
            if (isConfirmation)
            {
                ViewBag.Message = "Your reservation details have been saved as shown below:";
            }
            //otherwise, this is a search result
            else
            {
                ViewBag.Message = "Your current reservation details are as follows:";
            }
            //construct reservation object from database and pass it to the Details view
            Reservation reservation = db.Reservations.Find(id);
            if (reservation == null)
            {
                return RedirectToAction("Index", "Error");
            }
            return View(reservation);
        }

        //
        // GET: /Reservation/Create
        // returns create view
        public ActionResult Create(Reservation r = null)
        {
            //if this is the first attempt to reserve
            if (r.Name == null && r.Seats == 0)
            {
                return View();
            }
            //there was a previous failed attempt to reserve, display error message and previously entered details
            else
            {
                ViewBag.Message = "Sorry, we can not accommodate your booking as submitted";
                return View(r);
            }

        }

        //
        // POST: /Reservation/DoCreate
        //method to create a new reservation using data from form and add reservation to database
        [HttpPost]
        public ActionResult DoCreate(Reservation reservation)
        {
            if (ModelState.IsValid)
            {
                //find out how many seats are taken for the relevant date
                int usedSeats = 0;
                if (db.Reservations.Any(r => r.Date == reservation.Date))
                {
                    usedSeats = db.Reservations.Where(r => r.Date == reservation.Date).Sum(r => r.Seats);
                }
                //how much space is left for the relevant date?
                int freeSeats = Capacity.MaxDiners - usedSeats;
                //if there is enough space, complete the reservation and redirect to the details page for that reservation
                if (reservation.Seats <= freeSeats)
                {
                    db.Reservations.Add(reservation);
                    db.SaveChanges();
                    return RedirectToAction("Details", reservation);
                }
                //if there is not enough space, return to the reservation form
                else
                {
                    return RedirectToAction("Create", reservation);
                }
            }

            return RedirectToAction("Create", reservation);
        }

        //
        // GET: /Reservation/Edit/5
        //retrieves reservation info from database(based on id parameter) and passes it to the Edit view
        public ActionResult Edit(int id, bool fail = false)
        {
            Reservation reservation = db.Reservations.Find(id);
            //if someone entered a bogus reservation id into the url
            if (reservation == null)
            {
                return RedirectToAction("Index", "Error");
            }

            if (!fail)
            {
                ViewBag.Message = "";
                return View(reservation);
            }
            //the method was called due to a previous failed edit, display an error message
            else
            {
                ViewBag.Message = "Sorry, we can not accommodate your ammended reservation";
                return View(reservation);
            }
        }

        //
        // POST: /Reservation/Edit/5
        //method to overwrite reservation data in database with new data from edit form
        [HttpPost]
        public ActionResult Edit(Reservation reservation)
        {
            if (ModelState.IsValid)
            {
                //find out how many seats are taken for the relevant date and subtract the number allocated to the existing reservation
                int usedSeats = (db.Reservations.Where(r => r.Date == reservation.Date).Sum(r => r.Seats)) - (db.Reservations.Where(r => r.ID == reservation.ID).Sum(r => r.Seats));

                int freeSeats = Capacity.MaxDiners - usedSeats;
                //if there is enough space, complete the reservation and redirect to the details page for that reservation
                if (reservation.Seats <= freeSeats)
                {
                    db.Entry(reservation).State = EntityState.Modified;
                    db.SaveChanges();
                    return RedirectToAction("Details", new { id = reservation.ID });
                }
                //if there is not enough space, return to the editing form, where the error will be displayed
                else
                {
                    return RedirectToAction("Edit", new { id = reservation.ID, fail = true });
                }
            }
            return View(reservation);
        }

        //
        // GET: /Reservation/Delete/5
        //constructs a reservation object from database and returns delete view for that reservation
        [HttpGet]
        public ActionResult Delete(int id = 0)
        {
            Reservation reservation = db.Reservations.Find(id);
            if (reservation == null)
            {
                return RedirectToAction("Index", "Error");
            }
            return View(reservation);
        }

        //
        // POST: /Reservation/DoDelete/5
        // method to carry out deletion of a reservation based on id
        [HttpPost]
        public ActionResult DoDelete(int id)
        {
            Reservation reservation = db.Reservations.Find(id);
            db.Reservations.Remove(reservation);
            db.SaveChanges();
            //confirm the delete happened
            return RedirectToAction("DeleteConfirmed");
        }

        //returns a view to confirm the delete happened
        public ActionResult DeleteConfirmed()
        {
            return View();
        }

        protected override void Dispose(bool disposing)
        {
            db.Dispose();
            base.Dispose(disposing);
        }
    }
}